﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.ServiceModel.Description;
using System.Net.Security;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.IO;

namespace Service
{
    class Program
    {
        static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8000/ex");
            using (ServiceHost serviceHost = new ServiceHost(typeof(CalcService), baseAddress))
            {
                serviceHost.AddServiceEndpoint(typeof(IService), new WSHttpBinding(), "");
                ServiceMetadataBehavior smb = (ServiceMetadataBehavior)serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();

                if (smb == null)
                {
                    smb = new ServiceMetadataBehavior();
                    smb.HttpGetEnabled = true;
                    serviceHost.Description.Behaviors.Add(smb);
                }

                serviceHost.Open();

                // The service can now be accessed.
                Console.WriteLine("The service is ready.");
                Console.WriteLine("Press <ENTER> to terminate service.");
                Console.WriteLine();
                Console.ReadLine();
            }
        }
    }

    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        [FaultContract(typeof(MathFault), Action = "http://localhost:8000/MathFault", ProtectionLevel = ProtectionLevel.EncryptAndSign)]
        int Divede(int a, int b);
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = DebugHelper.IncludeExceptionDetailInFaults)]
    [ErrorBehavior(typeof(CalcErrorHandler))]
    public class CalcService : IService//, IErrorHandler
    {
        public int Divede(int a, int b)
        {
            if (b == 0)
                //throw new Exception("Division by zero!");
                throw new FaultException<MathFault>(new MathFault("Division by zero!"));

            return a / b;

        }

        //public bool HandleError(Exception error)
        //{
        //    using (TextWriter tw = File.AppendText(@"c:\logs\error.txt"))
        //    {
        //        if (error != null)
        //        {
        //            tw.WriteLine("Exception: " + error.GetType().Name + " - " + error.Message);
        //        }
        //        tw.Close();
        //    }
        //    return true;
        //}

        //public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        //{
        //}
    }

    public static class DebugHelper
    {
        public const bool IncludeExceptionDetailInFaults =
#if DEBUG
 true;
#else
        false;
#endif

        //public static Exception ExtractException(this FaultException<ExceptionDetail> fault);
    }


    #region

    public class CalcErrorHandler : IErrorHandler
    {
        // Provide a fault. The Message fault parameter can be replaced, or set to
        // null to suppress reporting a fault.

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
        }

        // HandleError. Log an error, then allow the error to be handled as usual.
        // Return true if the error is considered as already handled

        public bool HandleError(Exception error)
        {
            using (TextWriter tw = File.AppendText(@"c:\logs\error.txt"))
            {
                if (error != null)
                {
                    tw.WriteLine("Exception: " + error.GetType().Name + " - " + error.Message);
                }
                tw.Close();
            }
            return true;
        }
    }

    // This attribute can be used to install a custom error handler for a service.
    public class ErrorBehaviorAttribute : Attribute, IServiceBehavior
    {
        Type errorHandlerType;

        public ErrorBehaviorAttribute(Type errorHandlerType)
        {
            this.errorHandlerType = errorHandlerType;
        }

        void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
        }

        void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
        {
        }

        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler;

            try
            {
                errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
            }
            catch (MissingMethodException e)
            {
                throw new ArgumentException("The errorHandlerType specified in the ErrorBehaviorAttribute constructor must have a public empty constructor.", e);
            }
            catch (InvalidCastException e)
            {
                throw new ArgumentException("The errorHandlerType specified in the ErrorBehaviorAttribute constructor must implement System.ServiceModel.Dispatcher.IErrorHandler.", e);
            }

            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
    }

    #endregion


    // Define a math fault data contract
    [DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
    public class MathFault
    {
        private string operation;
        private string problemType;
        private string report;

        public MathFault(string msg)
        {
            // TODO: Complete member initialization
            this.report = msg;
        }

        [DataMember]
        public string Report
        {
            get { return report; }
            set { report = value; }
        }

        [DataMember]
        public string Operation
        {
            get { return operation; }
            set { operation = value; }
        }

        [DataMember]
        public string ProblemType
        {
            get { return problemType; }
            set { problemType = value; }
        }

    }


}
